﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace JMacia.Gaming.d20.Core.Traits
{
    public class Save : Trait, ID20Modifier
    {
        #region Private fields
        private bool _autoFail;
        private bool _autoSucceed;
        private Ability _keyAbility;
        #endregion

        #region Public static readonly fields
        public static readonly ModifierType[] StandardAllowedBonusTypes = new ModifierType[]{
            SystemModifierType.Alchemical,
            SystemModifierType.Circumstance,
            SystemModifierType.Insight,
            SystemModifierType.Luck,
            SystemModifierType.Morale,
            SystemModifierType.Profane,
            SystemModifierType.Racial,
            SystemModifierType.Resistance,
            SystemModifierType.Sacred,
            SystemModifierType.Untyped };
        public static readonly ModifierType[] StandardAllowedReflexBonusTypes = new ModifierType[]{
            SystemModifierType.Alchemical,
            SystemModifierType.Circumstance,
            SystemModifierType.Dodge,
            SystemModifierType.Insight,
            SystemModifierType.Luck,
            SystemModifierType.Morale,
            SystemModifierType.Profane,
            SystemModifierType.Racial,
            SystemModifierType.Resistance,
            SystemModifierType.Sacred,
            SystemModifierType.Untyped };
        #endregion

        #region Constructors

        public Save(int baseSave, Ability keyAbility)
            : this(string.Empty, baseSave, keyAbility, new Modifiers(),
            true, true, StandardAllowedBonusTypes)
        {
            AbilityType? type = keyAbility.Type;
            if (!type.HasValue || !KeyedToAbility(type.Value).HasValue)
            {
                throw new ArgumentException(
                    string.Format("Ability {0} has no linked save type",
                    keyAbility.Name), "keyAbility");
            }
        }

        public Save(SaveType name, int baseSave, Ability keyAbility)
            : this(name.ToString(), baseSave, keyAbility, new Modifiers(),
            true, true, StandardAllowedBonusTypes) { }

        public Save(SaveType name, int baseSave, Ability keyAbility, Modifiers modifiers)
            : this(name.ToString(), baseSave, keyAbility, modifiers, true, true, StandardAllowedBonusTypes) { }

        public Save(SaveType name, int baseSave, Ability keyAbility, Modifiers modifiers, bool autoSucceed, bool autoFail)
            : this(name.ToString(), baseSave, keyAbility, modifiers, autoSucceed, autoFail, StandardAllowedBonusTypes) { }

        public Save(string name, int baseSave, Ability keyAbility, Modifiers modifiers,
            bool autoSucceed, bool autoFail, params ModifierType[] allowedBonusTypes)
            : base(name, baseSave, modifiers, allowedBonusTypes)
        {
            if (keyAbility == null)
            {
                throw new ArgumentNullException("keyAbility", "Saves must have a key ability score.");
            }// if they pass in a null key ability, bail
            _keyAbility = keyAbility;
            _autoFail = autoFail;
            _autoSucceed = autoSucceed;
        }
        #endregion

        #region Public Static Methods
        public static SaveType? KeyedToAbility(AbilityType keyAbility)
        {
            switch (keyAbility)
            {
                case AbilityType.Constitution:
                    return SaveType.Fortitude;
                case AbilityType.Dexterity:
                    return SaveType.Reflex;
                case AbilityType.Wisdom:
                    return SaveType.Will;
                default:
                    return null;
            }
        }
        #endregion

        #region Public Properties
        public override int Total
        {
            get
            {
                return base.Total + _keyAbility.Modifier.TotalValue;
            }
        }

        public Ability KeyAbility
        {
            get { return _keyAbility; }
            set { _keyAbility = value; }
        }
        #endregion

        #region ID20Modifier Members

        public bool AutoSucceed
        {
            get
            {
                return _autoSucceed;
            }
            set
            {
                _autoSucceed = value;
            }
        }

        public bool AutoFail
        {
            get
            {
                return _autoFail;
            }
            set
            {
                _autoFail = value;
            }
        }

        #endregion
    }

    public enum SaveType
    {
        Fortitude,
        Reflex,
        Will,
    }
}
